/*
 * acooly.cn Inc.
 * Copyright (c) 2016 All Rights Reserved.
 * create by zhangpu
 * date:2016年3月20日
 *
 */
package com.ouwen.smartpay.service.notify;

import com.fm.common.emuns.MessageType;
import com.fm.common.emuns.TaskExecuteStatus;
import com.fm.common.emuns.TaskStatus;
import com.fm.common.order.NotifyOrder;
import com.fm.core.utils.Strings;
import com.fm.core.utils.net.HttpResult;
import com.fm.core.utils.net.Https;
import com.ouwen.smartpay.entity.NotifyDetail;
import com.ouwen.smartpay.entity.NotifyMessage;
import com.ouwen.smartpay.service.NotifyDetailService;
import com.ouwen.smartpay.service.NotifyMessageSendHandler;
import com.ouwen.smartpay.service.NotifyMessageService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/***
 *@author <a href="http://youngitman.tech">青年IT男</a>
 *@version v1.0.0
 *@className Http异步通知处理
 *@description
 *@JunitTest: {@link  }
 *@date
 *
 **/
@Component
public class HttpNotifyMessageSendHandler implements NotifyMessageSendHandler {

    private static Logger logger = LoggerFactory.getLogger(HttpNotifyMessageSendHandler.class);

    @Resource
    private NotifyMessageService notifyMessageService;

    @Resource
    private TaskExecutor notifyTaskExecutor;

    @Resource
    private NotifyDetailService notifyDetailService;

    private String connectionTimeout = String.valueOf(60);

    private String socketTimeout = String.valueOf(2 * 60);


    @Override
    public void send(final NotifyMessage notifyMessage, NotifyOrder order) {
        notifyTaskExecutor.execute(() -> doSend(notifyMessage));
    }

    protected void doSend(final NotifyMessage notifyMessage) {

        MDC.put("gid", notifyMessage.getGid());

        Date now = new Date();

        // 如果非第一次通知，下次通知时间还没有到，则忽略
        if (notifyMessage.getSendCount() != 0 && notifyMessage.getNextSendTime() != null && notifyMessage.getNextSendTime().after(now)) {

            return;
        }
        // 处理前锁定
        int rows = notifyMessageService.updateProccessingStatus(notifyMessage.getId());

        if (rows <= 0) {

            //被其他节点或线程处理了,放弃发送
            return;
        }

        notifyMessage.setSendCount(notifyMessage.getSendCount() + 1);

        logger.info("第{}次通知", notifyMessage.getSendCount());

        String result = null;

        String respInfo;

        try {

            logger.info("通知地址:{}", notifyMessage.getNotifyUrl());

            NotifyDetail notifyDetail = notifyDetailService.findOrderDetailNotifyInfoByOrderId(notifyMessage.getId());

            if (notifyDetail == null) {

                logger.warn("订单【{}】异步通知内容为空", notifyMessage.getMerchOrderNo());

                return;
            }

            logger.info("通知内容:{}", notifyDetail.getNotifyInfo());

            HttpResult httpResult = Https.getCustomInstance(connectionTimeout, socketTimeout).post(notifyMessage.getNotifyUrl(), notifyDetail.getNotifyInfo());

            result = httpResult.getBody();

            logger.info("通知结果:{}", httpResult);

            respInfo = httpResult.getStatus() + ":" + httpResult.getBody();

        } catch (Exception e) {

            respInfo = e.getMessage();

            logger.error("第{}次通知 失败，原因:{}", notifyMessage.getSendCount(), e.getMessage());

        }

        TaskStatus taskStatus;

        if (isSuccess(result)) {

            logger.info("第{}次通知成功", notifyMessage.getSendCount());

            taskStatus = TaskStatus.Success;

        } else {

            logger.info("第{}次通知失败", notifyMessage.getSendCount());

            int sendCount = notifyMessage.getSendCount();

            if (sendCount >= NotifyConfig.notifyCount) {

                taskStatus = TaskStatus.Finish;

                logger.info("通知失败次数达到阀值，结束通知任务");

            } else {

                taskStatus = TaskStatus.Waitting;

                notifyMessage.setNextSendTime(getNextNotifyTime(sendCount - 1));

                logger.info("通知失败次数未达到阀值，等待下次通知");

            }
        }

        notifyMessage.setStatus(taskStatus);

        notifyMessage.setExecuteStatus(TaskExecuteStatus.Unprocessed);

        if (Strings.length(respInfo) > 128) {

            respInfo = Strings.substring(respInfo, 0, 128);

        }

        notifyMessage.setRespInfo(respInfo);

        logger.info("通知消息保存: notifyMessage:{}", notifyMessage);

        notifyMessageService.update(notifyMessage);

        MDC.clear();

    }

    private static Date getNextNotifyTime(int num) {

        GregorianCalendar calendar = new GregorianCalendar();

        calendar.setTime(new Date());

        calendar.add(Calendar.MINUTE, NotifyConfig.notifyTime[num]);

        return calendar.getTime();

    }

    protected boolean isSuccess(String result) {

        if (result == null) {

            return false;
        }

        result = result.toLowerCase();

        if ("success".equals(result)) {

            return true;

        }

        result = result.replaceAll("\\s*", "");

        if ("success".equals(result)) {

            return true;

        }

        return result.length() < 50 && result.contains("success");

    }

    @Override
    public MessageType getNotifyMessageType() {

        return MessageType.HTTP;

    }

}
